import { APP_INITIALIZER, Injectable, Provider, inject } from '@angular/core';
import { ACLService } from '@delon/acl';
import { DA_SERVICE_TOKEN, ITokenService, JWTTokenModel } from '@delon/auth';
import { ALAIN_I18N_TOKEN, App, Menu, MenuService, SettingsService, TitleService, User } from '@delon/theme';
import { environment } from '@env/environment';
import { NzSafeAny } from 'ng-zorro-antd/core/types';
import { Observable, zip } from 'rxjs';
import { catchError, map } from 'rxjs/operators';

import { AfMenu, NgMenu } from './af-menus';
import { AfMessageService } from './af-message.service';
import { AfSecurityService } from './af-security.service';
import { substring } from './af-string-util';
import { I18NService } from '../i18n/i18n.service';

/**
 * @Author: asushiye
 * @Date: 2020-07-02 15:30:23
 * @Commit: file conten
 * Used for application startup
 * Generally used to get the basic data of the application, like: Menu Data, User Data, etc.
 */

/**
 * Used for application startup
 * Generally used to get the basic data of the application, like: Menu Data, User Data, etc.
 */
export function provideStartup(): Provider[] {
  return [
    StartupService,
    {
      provide: APP_INITIALIZER,
      useFactory: (startupService: StartupService) => () => startupService.load(),
      deps: [StartupService],
      multi: true
    }
  ];
}

@Injectable()
export class StartupService {
  public access_token: String = '';
  private readonly menuService = inject(MenuService);
  private settingService = inject(SettingsService);
  private aclService = inject(ACLService);
  private titleService = inject(TitleService);
  private i18n = inject<I18NService>(ALAIN_I18N_TOKEN);
  private tokenService = inject<ITokenService>(DA_SERVICE_TOKEN);
  private readonly security = inject(AfSecurityService);
  private readonly msgSrv = inject(AfMessageService);
  constructor() {}

  // 用于系统启动时初始化数据， 在登入成功或身份自动认证后触发
  load(): Observable<void> {
    const defaultLang = this.i18n.defaultLang;
    return this.i18n.loadLangData(defaultLang).pipe(
      map((langData: NzSafeAny) => {
        this.i18n.use(defaultLang, langData);

        this.loadAuthData();
      })
    );
  }
  loadAuthData() {
    this.security
      .getAuthData(true, false, false)
      .pipe(
        catchError(res => {
          console.warn(`StartupService.load: Network request failed`, res);
          return [];
        })
      )
      .subscribe(res => {
        if (res.status) {
          this.setAuthData(res);
        } else {
          this.msgSrv.msg_warning('用户暂无权限，请系统管理员分配菜单权限！', { nzDuration: 10000 });
        }
      });
  }

  // 设置user, app, menu 数据
  private setAuthData(result: any) {
    console.log(`StartupService.load, obtained remote authentication data`);
    // 解析返回值, 数据结构，请参考 common- README.md文档
    const appData: any = result.data.app;
    const userData: any = result.data.user;
    const menuData: Menu[] = result.data.menus;

    // set application data
    this.setApp(appData);
    // set user data
    this.setUser(userData);
    // set menu data, https://ng-alain.com/theme/menu
    this.setMenus(menuData, true);
    // set acl data, , https://ng-alain.com/acl/getting-started
    this.setAcl(null);
    // set page title, https://ng-alain.com/theme/title
    this.setTitle(appData.name);

    console.log('StartupService.load, Complete authentication data loading');
  }

  private setApp(appData: any) {
    console.debug('app', JSON.stringify(appData));

    const app: App = {
      name: appData.name,
      description: appData.description
    };
    this.settingService.setApp(app);
  }

  private setUser(userData: any) {
    console.debug('user', JSON.stringify(userData));
    let userName = userData.username;
    // 记录登录的账号信息
    this.security.userAccount.username = userName;

    // 从JWT获取更详细用户信息
    // const jwtToken = this.tokenService.get<JWTTokenModel>(JWTTokenModel);
    // const jwt = jwtToken!.payload;
    // console.log(JSON.stringify(jwt));

    const user: User = {
      id: userData.username,
      name: userData.nickName ? userData.nickName : userData.username,
      phone: userData.phone,
      shortName: substring(userData.username, 3, 'U'),
      email: userData.email,
      avatar: './assets/tmp/img/avatar.jpg'
    };

    this.settingService.setUser(user);
  }

  // onlyDev=true 仅仅时本地菜单
  private setMenus(menusData: any, showDemo: boolean = true) {
    // console.debug('menus', JSON.stringify(menusData));

    this.setTokenForMenus(menusData);
    if (environment.production) {
      if (menusData && menusData.length >= 1) {
        this.menuService.add(menusData);
      }
    } else {
      const afMenu = AfMenu as NzSafeAny;
      const ngMenu = NgMenu as NzSafeAny;
      this.setTokenForMenus(afMenu);
      if (showDemo) {
        this.menuService.add([...afMenu, ...ngMenu]);
      } else {
        this.menuService.add([...afMenu]);
      }
    }
  }

  //为积木报表添加access_token
  private setTokenForMenus(items: Menu[]) {
    if (items && items.length >= 1) {
      const jwtToken = this.tokenService.get<JWTTokenModel>(JWTTokenModel);
      items.forEach(item => {
        if (!(item.externalLink === undefined || item.externalLink === '')) {
          if (item.externalLink.indexOf('jmreport') != -1) {
            if (item.externalLink.indexOf('?') != -1) {
              item.externalLink = this.getExtrenalLink(item.externalLink, jwtToken.token, '&');
            } else {
              item.externalLink = this.getExtrenalLink(item.externalLink, jwtToken.token, '?');
            }
          }
        }

        if (item.children !== undefined && item.children.length >= 1) {
          this.setTokenForMenus(item.children);
        }
      });
    }
  }

  private getExtrenalLink(value: String, token: any, cha: string) {
    const iIndex = value.lastIndexOf('token=');
    if (iIndex == -1) {
      return value.concat(cha).concat('token=').concat(token);
    }
    return value.substring(0, iIndex).concat(cha).concat('token=').concat(token);
  }

  private setAcl(aclData: any) {
    // default the permissions to full
    this.aclService.setFull(true);
  }
  private setTitle(title: any) {
    this.titleService.setTitle(title);
    this.titleService.suffix = 'af';
  }
}
